/**
 * Title: codegen.h
 * Description: LLVM-IR code generation and semantic analysis for AST
 * Copyright: Copyright (c) 2022
 * Company: Beijing University of Posts and Telecommunications
 * @author 2019211323 龙宣燕 2019211325 王熙媛 2019211410 王敏行 2019211416 邹宇江
 * @date 2022/04/14 13:04 GMT+08:00
 * @version 0.9.0-beta
 */

#ifndef _CODEGEN_H
#define _CODEGEN_H

#include "llvm/ADT/APInt.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/Value.h"
#include "llvm/Bitcode/BitcodeWriter.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/InstCombine/InstCombine.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Scalar/GVN.h"
#include <memory>
#include <cstdio>
#include <iostream>
#include <fstream>
#include "../ast/ast.h"
#include "../symbol/codegen.symbol.h"

class CodeGen : public Visitor {
private:
    std::unique_ptr<llvm::LLVMContext> TheContext;
    std::unique_ptr<llvm::Module> TheModule;
    std::unique_ptr<llvm::IRBuilder<>> Builder;
    std::unique_ptr<Scope> SymbolStack;

    llvm::FunctionType *PrintfTy;
    llvm::Function *Printf;
    llvm::FunctionType *ScanfTy;
    llvm::Function *Scanf;

    FILE *Log;

    int TempParamCnt;

    int error(const char *format, ...) {
        va_list args;
        va_start(args, format);
        fprintf(stderr, "error: ");
        vfprintf(stderr, format, args);
        fprintf(stderr, "\n");
        va_end(args);
        exit(1);
    }
    int warning(const char *format, ...) {
        va_list args;
        va_start(args, format);
        fprintf(stderr, "warning: ");
        vfprintf(stderr, format, args);
        fprintf(stderr, "\n");
        va_end(args);
        return 0;
    }
    int log(const char *format, ...) {
        va_list args;
        va_start(args, format);
        time_t t = time(NULL);
        char* ct = ctime(&t);
        ct[strlen(ct) - 1] = '\0';
        fprintf(Log, "%s ", ct);
        vfprintf(Log, format, args);
        va_end(args);
        return 0;
    }

public:
    CodeGen() {
        TheContext = std::make_unique<llvm::LLVMContext>();
        TheModule = std::make_unique<llvm::Module>("Pascal-S", *TheContext);
        Builder = std::make_unique<llvm::IRBuilder<>>(*TheContext);
        SymbolStack = std::make_unique<Scope>();
        PrintfTy = nullptr;
        Printf = nullptr;
        ScanfTy = nullptr;
        Scanf = nullptr;
        Log = fopen("yapsc.log", "a");
        TempParamCnt = 0;
    }

    ~CodeGen() {
        fclose(Log);
    }

    void dump() { TheModule->print(llvm::outs(), nullptr); }
    void write(std::string filename) {
        std::error_code ec;
        llvm::raw_ostream *os = new llvm::raw_fd_ostream(filename, ec, llvm::sys::fs::F_None);
        llvm::WriteBitcodeToFile(*TheModule, *os);
        os->flush();
        delete os;
    }

    void *visit(AST *node) final { return nullptr; }

    void *visit(ProgramAST *node) final {
        SymbolStack->push();
        log("Start program\n");

        //返回值类型
        llvm::Type *retType = llvm::Type::getVoidTy(*TheContext);

        //函数类型
        llvm::FunctionType *funcType = llvm::FunctionType::get(retType, false);
        const std::string funcName = "main";
        llvm::Function *mainFunc = llvm::Function::Create(funcType, llvm::Function::ExternalLinkage, funcName, *TheModule);
        const std::string entryName = node->get_head()->get_name() + "-Entry";
        llvm::BasicBlock *entry = llvm::BasicBlock::Create(*TheContext, entryName, mainFunc);
        Builder->SetInsertPoint(entry);

        node->get_head()->accept(this);
        node->get_block()->accept(this);

        // Builder->SetInsertPoint(entry);
        //返回值
        Builder->CreateRetVoid();

        SymbolStack->pop();

        return nullptr;
    }

    void *visit(ProgramHeadingAST *node) final { return nullptr; }

    void *visit(ProgramBlockAST *node) final {
        node->get_block()->accept(this);
        return nullptr;
    }

    void *visit(BlockAST *node) final {
        if (nullptr != node->get_const()) {
            node->get_const()->accept(this);
        }
        if (nullptr != node->get_type()) {
            node->get_type()->accept(this);
        }
        if (nullptr != node->get_var()) {
            node->get_var()->accept(this);
        }
        if (nullptr != node->get_proc()) {
            node->get_proc()->accept(this);
        }
        node->get_stmt()->accept(this);
        return nullptr;
    }

    void *visit(ProgramParametersAST *node) final { return nullptr; }

    void *visit(IdentifierListAST *node) final { return nullptr; }

    void *visit(ConstantDefinitionListAST *node) final {
        std::vector<ConstantDefinitionAST *> constList = node->get_const_list();
        for (auto iter = constList.begin(); iter != constList.end(); iter++) {
            (*iter)->accept(this);
        }
        return nullptr;
    }

    void *visit(ConstantDefinitionAST *node) final {
        if (ConstantAST::Type::IDENTIFIER == node->get_val()->type()) {
            error("not support initializing new constant with constant identifier");
            return nullptr;
        }


        llvm::Constant *v = (llvm::Constant *)node->get_val()->accept(this);
        std::string name = node->get_id();

        if (node->get_val()->type() == ConstantAST::Type::STRING) { // string类型的单独处理
            llvm::Constant *s = llvm::ConstantDataArray::getString(*TheContext, node->get_val()->value());
            llvm::Value *constStr = new llvm::GlobalVariable(*TheModule, s->getType(), true, llvm::GlobalValue::PrivateLinkage, s, name);
        }
        else {
            llvm::GlobalVariable *constant = new llvm::GlobalVariable(*TheModule, v->getType(), true, llvm::GlobalValue::PrivateLinkage, v, name);
            // constant->setInitializer(v);
            // Builder->CreateStore(v, constant);//此句好像可以不加
        }
        if (!SymbolStack->is_local(name)) {
            SymbolStack->insertConstant(name, v);
        }
        else {
            error("Constant error[duplicate definition %s]", name.c_str());
            return nullptr;
        }

        return nullptr;
    }

    void *visit(TypeDefinitionListAST *node) final {
        std::vector<TypeDefinitionAST *> typeList = node->get_type_list();
        for (auto iter = typeList.begin(); iter != typeList.end(); iter++) {
            (*iter)->accept(this);
        }
        return nullptr;
    }

    void *visit(TypeDefinitionAST *node) final {
        switch (node->get_type()->type()) {
        case TypeDenoterAST::Type::SIMPLE: {
            SimpleTypeIdentifierAST *snode = static_cast<SimpleTypeIdentifierAST *>(node->get_type());
            llvm::Type *type = static_cast<llvm::Type *>(snode->accept(this));
            if (0 != SymbolStack->insertAlias(node->get_id(), type)) {
                error("duplicate identifier \"%s\"", node->get_id().c_str());
                return nullptr;
            }
            break;
        }
        case TypeDenoterAST::Type::ARRAY: {
            ArrayTypeAST *anode = static_cast<ArrayTypeAST *>(node->get_type());
            llvm::ArrayType *array = static_cast<llvm::ArrayType *>(anode->accept(this));
            if (nullptr == array) {
                return nullptr;
            }
            int beg;
            try {
                beg = std::stoi(anode->get_per_list()->get_per_list().front()->get_beg()->value());
            }
            catch (...) {
                auto cib = llvm::dyn_cast<llvm::ConstantInt>(static_cast<llvm::Value *>(
                    anode->get_per_list()->get_per_list().front()->get_beg()->accept(this)));
                beg = cib->getSExtValue();
            }
            int end = array->getArrayNumElements() + beg - 1;
            int ret = SymbolStack->insertArray(node->get_id(), array, beg, end);
            if (0 != ret) {
                error("duplicate identifier \"%s\"", node->get_id().c_str());
                return nullptr;
            }
            break;
        }
        case TypeDenoterAST::Type::RECORD: {
            RecordTypeAST *rnode = static_cast<RecordTypeAST *>(node->get_type());
            llvm::StructType *record = static_cast<llvm::StructType *>(rnode->accept(this));
            std::vector<std::string> field;
            for (auto &i : rnode->get_field_list()->get_field_list()) {
                for (auto &j : i->get_id_list()->get_id_list()) {
                    field.push_back(j);
                }
            }
            if (field.size() != record->elements().size()) {
                error("record elements size is not equal to identifiers size. aborting");
                return nullptr;
            }
            if (0 != SymbolStack->insertRecord(node->get_id(), record, field)) {
                error("duplicate identifier \"%s\"", node->get_id().c_str());
                return nullptr;
            }
            break;
        }
        default:
            error("current type is not supported in type definition");
            break;
        }
        return nullptr;
    }

    void *visit(VariableDeclarationListAST *node) final {
        std::vector<VariableDeclarationAST *> varList = node->get_var_list();
        for (auto iter = varList.begin(); iter != varList.end(); iter++) {
            (*iter)->accept(this);
        }
        return nullptr;
    }

    void *visit(VariableDeclarationAST *node) final {
        std::vector<std::string> idList = node->get_id_list()->get_id_list();

        // Used for symbol table
        std::string varType = "";
        std::shared_ptr<Symbol> ref = nullptr;
        if (TypeDenoterAST::Type::SIMPLE != node->get_type()->type()) {
            if (TypeDenoterAST::Type::IDENTIFIER == node->get_type()->type()) {
                auto tid = static_cast<TypeIdentifierAST *>(node->get_type());
                auto symbol = SymbolStack->find(tid->get_id(), Symbol::Type::PTYPE);
                if (nullptr == symbol) {
                    error("unknown type id %s", tid->get_id().c_str());
                    return nullptr;
                }
                if (Symbol::Type::ALIAS != symbol->type()) {
                    varType = tid->get_id();
                    ref = symbol;
                }
            }
            else {
                error("Only support simple and type identifier in variable declaration");
                return nullptr;
            }
        }

        llvm::Type *type = static_cast<llvm::Type *>(node->get_type()->accept(this));

        for (std::string id : idList) {
            if (1 == SymbolStack->depth()) { //定义在program内，相当于全局变量
                llvm::Constant *initializer; //全局变量的初始值

                if (node->get_type()->type() == TypeDenoterAST::Type::SIMPLE) {
                    initializer = llvm::Constant::getNullValue(type);
                }
                else
                    initializer = llvm::ConstantAggregateZero::get(type);


                llvm::GlobalVariable *gloVar = new llvm::GlobalVariable(*TheModule, type, false, llvm::GlobalValue::CommonLinkage, initializer, id);
                if (0 != SymbolStack->insertVariable(id, gloVar, varType, ref)) {
                    error("duplicate identifier \"%s\"", id.c_str());
                    return nullptr;
                }

                // Builder->CreateStore(initializer, gloVar);
            }
            else {
                llvm::AllocaInst *locVar = Builder->CreateAlloca(type, nullptr, id);
                if (0 != SymbolStack->insertVariable(id, locVar, varType, ref)) {
                    error("duplicate identifier \"%s\"", id.c_str());
                    return nullptr;
                }
            }
        }
        return nullptr;
    }

    void *visit(ProcedureFunctionDeclarationListAST *node) final {
        std::vector<SubprogramDeclarationAST *> subProgList = node->get_sub_list();
        for (auto iter = subProgList.begin(); iter != subProgList.end(); iter++) {
            (*iter)->accept(this);
        }
        return nullptr;
    }

    void *visit(SubprogramDeclarationAST *node) final { return nullptr; }

    void *visit(ProcedureDeclarationAST *node) final {
        std::string procName = node->get_head()->get_name();
        log("Procedure %s\n", procName.c_str());

        std::vector<std::string> allParamName;                //所有的形式参数名
        std::vector<llvm::Type *> allParamType;               //所有的类型,和上面对应
        std::vector<std::string> allParamTypeID;              //所有的类型ID,和上面对应
        std::vector<std::shared_ptr<Symbol>> allParamTypeSym; //所有的类型符号,和上面对应
        std::vector<bool> allParamIsVar;                      //参数是否是传引用，是为true,也和上面对应

        //处理参数
        std::vector<FormalParameterSectionAST *> params = node->get_head()->get_params()->get_params();

        for (FormalParameterSectionAST *formParam : params) {
            switch (formParam->type()) {
            case FormalParameterSectionAST::Type::VALUE: { //传值
                ValueParameterSpecificationAST *valueParam = static_cast<ValueParameterSpecificationAST *>(formParam);
                llvm::Type *type = static_cast<llvm::Type *>(valueParam->get_type()->accept(this));
                std::vector<std::string> nameList = valueParam->get_id_list()->get_id_list();
                for (std::string name : nameList) {
                    allParamName.push_back(name);
                    allParamType.push_back(llvm::PointerType::getUnqual(type));
                    allParamIsVar.push_back(false);
                    if (valueParam->get_type()->type() == TypeDenoterAST::Type::SIMPLE) {
                        allParamTypeID.push_back("");
                        allParamTypeSym.push_back(nullptr);
                    }
                    else {
                        allParamTypeID.push_back(static_cast<TypeIdentifierAST *>(valueParam->get_type())->get_id());
                        allParamTypeSym.push_back(SymbolStack->find(allParamTypeID.back()));
                    }
                }
                break;
            }
            case FormalParameterSectionAST::Type::VARIABLE: { //传引用
                VariableParameterSpecificationAST *varParam = static_cast<VariableParameterSpecificationAST *>(formParam);
                llvm::Type *type = static_cast<llvm::Type *>(varParam->get_type()->accept(this));
                std::vector<std::string> nameList = varParam->get_id_list()->get_id_list();
                for (std::string name : nameList) {
                    allParamName.push_back(name);
                    allParamType.push_back(llvm::PointerType::getUnqual(type));
                    allParamIsVar.push_back(true);
                    if (varParam->get_type()->type() == TypeDenoterAST::Type::SIMPLE) {
                        allParamTypeID.push_back("");
                        allParamTypeSym.push_back(nullptr);
                    }
                    else {
                        allParamTypeID.push_back(static_cast<TypeIdentifierAST *>(varParam->get_type())->get_id());
                        allParamTypeSym.push_back(SymbolStack->find(allParamTypeID.back()));
                    }
                }
                break;
            }
            default:
                break;
            }
        }
        //检查参数是否重名
        if (0 != allParamName.size()) {
            for (int i = 0; i < allParamName.size() - 1; i++) {
                for (int j = i + 1; j < allParamName.size(); j++) {
                    if (allParamName[i] == allParamName[j]) {
                        error("The parameter %s in procedure %s is duplicated", allParamName[i].c_str(), procName.c_str());
                        return nullptr;
                    }
                }
            }
        }

        llvm::Type *retType = llvm::Type::getVoidTy(*TheContext);

        llvm::FunctionType *functionType = llvm::FunctionType::get(retType, allParamType, false); // false表示参数个数不可变
        llvm::Function *function = llvm::Function::Create(functionType, llvm::GlobalValue::ExternalLinkage, procName, *TheModule);

        if (0 != SymbolStack->insertFunction(procName, function, allParamIsVar)) {
            error("duplicate procdure %s", procName.c_str());
            return nullptr;
        }
        SymbolStack->push();

        //获取参数的引用，并加入符号表
        std::vector<std::shared_ptr<SymbolVariable>> paramsForInsert;
        int i = 0;
        for (llvm::Function::arg_iterator argIt = function->arg_begin(); argIt != function->arg_end(); argIt++, i++) {
            argIt->setName(allParamName[i]);
            SymbolStack->insertVariable(allParamName[i], argIt, allParamTypeID[i], allParamTypeSym[i]); //此处不用再查重

            std::shared_ptr<Symbol> t = (std::shared_ptr<Symbol>)(new Symbol(Symbol::Type::VARIABLE));
            SymbolVariable *s = new SymbolVariable(argIt, "", t);
            paramsForInsert.push_back((std::shared_ptr<SymbolVariable>)(s));
        }

        llvm::BasicBlock *oldBlock = Builder->GetInsertBlock();
        llvm::BasicBlock *block = llvm::BasicBlock::Create(*TheContext, procName + "-entry", function, nullptr);
        Builder->SetInsertPoint(block);
        node->get_body()->accept(this);
        Builder->CreateRetVoid();

        Builder->SetInsertPoint(oldBlock);
        SymbolStack->pop();

        return nullptr;
    }

    void *visit(ProcedureHeadingAST *node) final { return nullptr; }

    void *visit(ProcedureBodyAST *node) final {
        return node->get_block()->accept(this);
    }

    void *visit(TypeDenoterAST *node) final { return nullptr; }

    void *visit(FunctionDeclarationAST *node) final {
        std::string funcName = node->get_head()->get_name();
        log("Function %s\n", funcName.c_str());

        std::vector<std::string> allParamName;                //所有的形式参数名
        std::vector<llvm::Type *> allParamType;               //所有的类型,和上面对应
        std::vector<std::string> allParamTypeID;              //所有的类型ID,和上面对应
        std::vector<std::shared_ptr<Symbol>> allParamTypeSym; //所有的类型符号,和上面对应
        std::vector<bool> allParamIsVar;                      //参数是否是传引用，是为true,也和上面对应

        //处理参数
        std::vector<FormalParameterSectionAST *> params = node->get_head()->get_params()->get_params();

        for (FormalParameterSectionAST *formParam : params) {
            switch (formParam->type()) {
            case FormalParameterSectionAST::Type::VALUE: { //传值
                ValueParameterSpecificationAST *valueParam = static_cast<ValueParameterSpecificationAST *>(formParam);
                llvm::Type *type = static_cast<llvm::Type *>(valueParam->get_type()->accept(this));
                std::vector<std::string> nameList = valueParam->get_id_list()->get_id_list();
                for (std::string name : nameList) {
                    allParamName.push_back(name);
                    allParamType.push_back(llvm::PointerType::getUnqual(type));
                    allParamIsVar.push_back(false);
                    if (valueParam->get_type()->type() == TypeDenoterAST::Type::SIMPLE) {
                        allParamTypeID.push_back("");
                        allParamTypeSym.push_back(nullptr);
                    }
                    else {
                        allParamTypeID.push_back(static_cast<TypeIdentifierAST *>(valueParam->get_type())->get_id());
                        allParamTypeSym.push_back(SymbolStack->find(allParamTypeID.back()));
                    }
                }
                break;
            }
            case FormalParameterSectionAST::Type::VARIABLE: { //传引用
                VariableParameterSpecificationAST *varParam = static_cast<VariableParameterSpecificationAST *>(formParam);
                llvm::Type *type = static_cast<llvm::Type *>(varParam->get_type()->accept(this));
                std::vector<std::string> nameList = varParam->get_id_list()->get_id_list();
                for (std::string name : nameList) {
                    allParamName.push_back(name);
                    allParamType.push_back(llvm::PointerType::getUnqual(type));
                    allParamIsVar.push_back(true);
                    if (varParam->get_type()->type() == TypeDenoterAST::Type::SIMPLE) {
                        allParamTypeID.push_back("");
                        allParamTypeSym.push_back(nullptr);
                    }
                    else {
                        allParamTypeID.push_back(static_cast<TypeIdentifierAST *>(varParam->get_type())->get_id());
                        allParamTypeSym.push_back(SymbolStack->find(allParamTypeID.back()));
                    }
                }
                break;
            }
            default:
                break;
            }
        }
        //检查参数是否重名
        if (0 != allParamName.size()) {
            for (int i = 0; i < allParamName.size() - 1; i++) {
                for (int j = i + 1; j < allParamName.size(); j++) {
                    if (allParamName[i] == allParamName[j]) {
                        error("The parameter %s in function %s is duplicated", allParamName[i].c_str(), funcName.c_str());
                        return nullptr;
                    }
                }
            }
        }

        llvm::Type *retType = static_cast<llvm::Type *>(node->get_head()->get_ret_type()->accept(this));

        llvm::FunctionType *functionType = llvm::FunctionType::get(retType, allParamType, false); // false表示参数个数不可变
        llvm::Function *function = llvm::Function::Create(functionType, llvm::GlobalValue::ExternalLinkage, funcName, *TheModule);

        if (0 != SymbolStack->insertFunction(funcName, function, allParamIsVar)) {
            error("duplicate function %s", funcName.c_str());
            return nullptr;
        }
        SymbolStack->push();

        //获取参数的引用，并加入符号表
        std::vector<std::shared_ptr<SymbolVariable>> paramsForInsert;
        int i = 0;
        for (llvm::Function::arg_iterator argIt = function->arg_begin(); argIt != function->arg_end(); argIt++, i++) {
            argIt->setName(allParamName[i]);
            SymbolStack->insertVariable(allParamName[i], argIt, allParamTypeID[i], allParamTypeSym[i]); //此处不用再查重

            std::shared_ptr<Symbol> t = (std::shared_ptr<Symbol>)(new Symbol(Symbol::Type::VARIABLE));
            SymbolVariable *s = new SymbolVariable(argIt, "", t);
            paramsForInsert.push_back((std::shared_ptr<SymbolVariable>)(s));
        }

        llvm::BasicBlock *oldBlock = Builder->GetInsertBlock();
        llvm::BasicBlock *block = llvm::BasicBlock::Create(*TheContext, funcName + "-entry", function, nullptr);
        Builder->SetInsertPoint(block);

        //返回值,返回值名字和函数一样，应该是在其他地方修改这个值
        llvm::AllocaInst *mem = Builder->CreateAlloca(retType, nullptr, funcName);
        SymbolStack->insertVariable(funcName, mem);

        node->get_body()->accept(this);

        llvm::Value *retValue = Builder->CreateLoad(mem);
        Builder->CreateRet(retValue);

        Builder->SetInsertPoint(oldBlock);
        SymbolStack->pop();

        return nullptr;
    }

    void *visit(FunctionHeadingAST *node) final { return nullptr; }

    void *visit(FunctionBodyAST *node) final {
        return node->get_block()->accept(this);
    }

    void *visit(FormalParameterListAST *node) final { return nullptr; }

    void *visit(FormalParameterSectionAST *node) final { return nullptr; }

    void *visit(ValueParameterSpecificationAST *node) final { return nullptr; }

    void *visit(VariableParameterSpecificationAST *node) final { return nullptr; }

    void *visit(ConstantAST *node) final {
        llvm::Type *constType = nullptr;
        std::string valueInString = node->value();
        bool isNegative = node->sign() == '-' ? true : false;

        switch (node->type()) {
        case ConstantAST::Type::BOOLEAN: {
            // constType = llvm::Type::getInt1Ty(*TheContext);
            for (int i = 0; i < valueInString.length(); i++)
                valueInString[i] = tolower(valueInString[i]);
            bool v = valueInString == "true" ? true : false;

            // llvm::Constant *constBool = llvm::ConstantInt::get(constType, (uint64_t)v, true);
            llvm::Constant *constBool = v ? Builder->getTrue() : Builder->getFalse();
            return constBool;
        }
        case ConstantAST::Type::CHARACTER: {
            if (valueInString.length() > 3) {
                std::string str(valueInString.begin() + 1, valueInString.end() - 1);
                llvm::Constant *s = llvm::ConstantDataArray::getString(*TheContext, str);
                llvm::Value *constStr = new llvm::GlobalVariable(*TheModule, s->getType(), true, llvm::GlobalValue::PrivateLinkage, s, "");
                return constStr;
            }
            else {
                constType = llvm::Type::getInt8Ty(*TheContext);
                char v = valueInString[1];
                llvm::Constant *constChar = llvm::ConstantInt::getSigned(constType, v);
                return constChar;
            }
        }
        case ConstantAST::Type::INTEGER: {
            constType = llvm::Type::getInt32Ty(*TheContext);
            int v = std::stoi(valueInString);
            if (isNegative)
                v = -v;
            llvm::Constant *constInt = llvm::ConstantInt::getSigned(constType, v);
            return constInt;
        }
        case ConstantAST::Type::REAL: {
            constType = llvm::Type::getDoubleTy(*TheContext);
            double v = std::stof(valueInString);
            if (isNegative)
                v = -v;
            llvm::Constant *constReal = llvm::ConstantFP::get(constType, v);
            return constReal;
        }
        case ConstantAST::Type::IDENTIFIER: {
            // Actual parameter can be constant
            // write() can print somthing like a[]
            // But we only handle simple constant value
            // write() will handle array itself
            auto symbol = SymbolStack->find(node->value());
            if (nullptr == symbol) {
                error("identifier \"%s\" is undefined", node->value().c_str());
                return nullptr;
            }
            // ConstantAST::Type::IDENTIFIER represents variable_access
            // so that id may be variable
            if (Symbol::Type::VARIABLE == symbol->type()) {
                return std::dynamic_pointer_cast<SymbolVariable>(symbol)->getValue();
            }
            else if (Symbol::Type::CONSTANT == symbol->type()) {
                return std::dynamic_pointer_cast<SymbolConstant>(symbol)->getValue();
            }
            else {
                error("identifier \"%s\" is not variable or constant", node->value().c_str());
                return nullptr;
            }
        }
        default:
            return nullptr;
        }
    }

    void *visit(TypeIdentifierAST *node) final {
        auto ret = SymbolStack->find(node->get_id(), Symbol::Type::PTYPE);
        if (nullptr == ret) {
            error("type identifier %s not found.", node->get_id().c_str());
            return nullptr;
        }
        switch (ret->type()) {
        case Symbol::Type::ALIAS:
            return std::dynamic_pointer_cast<SymbolAlias>(ret)->getType();
        case Symbol::Type::ARRAY:
            return std::dynamic_pointer_cast<SymbolArray>(ret)->getArray();
        case Symbol::Type::RECORD:
            return std::dynamic_pointer_cast<SymbolRecord>(ret)->getRecord();
        default:
            return nullptr;
        }
    }

    void *visit(SimpleTypeIdentifierAST *node) final {
        switch (node->std_type()) {
        case SimpleTypeIdentifierAST::StandardType::INTEGER:
            return llvm::Type::getInt32Ty(*TheContext);
        case SimpleTypeIdentifierAST::StandardType::REAL:
            return llvm::Type::getDoubleTy(*TheContext);
        case SimpleTypeIdentifierAST::StandardType::BOOLEAN:
            return llvm::Type::getInt1Ty(*TheContext);
        case SimpleTypeIdentifierAST::StandardType::CHARACTER:
            return llvm::Type::getInt8Ty(*TheContext);
        case SimpleTypeIdentifierAST::StandardType::STRING:
            // To be determined
            return llvm::ArrayType::get(llvm::Type::getInt8Ty(*TheContext), 128);
        default:
            return nullptr;
        }
    }

    void *visit(ArrayTypeAST *node) final {
        // Element type must be simple
        llvm::Type *eType;
        switch (node->get_type()->type()) {
        case TypeDenoterAST::Type::SIMPLE:
            eType = static_cast<llvm::Type *>(node->get_type()->accept(this));
            break;
        case TypeDenoterAST::Type::IDENTIFIER: {
            std::string id = static_cast<TypeIdentifierAST *>(node->get_type())->get_id();
            auto ret = SymbolStack->find(id);
            if (nullptr == ret) {
                error("identifier \"%s\" is undefined", id.c_str());
                return nullptr;
            }
            if (Symbol::Type::ALIAS == ret->type()) {
                eType = std::dynamic_pointer_cast<SymbolAlias>(ret)->getType();
                break;
            }
            // no break
        }
        default:
            error("array only support simple base type");
            return nullptr;
        }

        // Only support one-dimensional array
        if (node->get_per_list()->get_per_list().size() != 1) {
            error("array only support one-dimensional");
            return nullptr;
        }

        // Here is an example of getting int value from llvm::Constant
        // You can just directly access ConstantAST and use C++ lib
        uint64_t eNum;
        auto cb = static_cast<llvm::Value *>(node->get_per_list()->get_per_list().front()->get_beg()->accept(this));
        auto ce = static_cast<llvm::Value *>(node->get_per_list()->get_per_list().front()->get_end()->accept(this));
        llvm::ConstantInt *cib;
        llvm::ConstantInt *cie;
        // Period must be integer32 and diff > 0
        if ((cib = llvm::dyn_cast<llvm::ConstantInt>(cb)) && (cie = llvm::dyn_cast<llvm::ConstantInt>(ce)) && cib->getBitWidth() == 32 && cie->getBitWidth() == 32) {
            eNum = cie->getSExtValue() - cib->getSExtValue() + 1;
            if (eNum > 0) {
                return llvm::ArrayType::get(eType, eNum);
            }
            else {
                error("array period invalid.");
                return nullptr;
            }
        }
        else {
            error("array period not integer.");
            return nullptr;
        }
    }

    void *visit(PeriodListAST *node) final { return nullptr; }

    void *visit(PeriodAST *node) final { return nullptr; }

    void *visit(RecordTypeAST *node) final {
        std::vector<llvm::Type *> elem;
        for (auto &i : node->get_field_list()->get_field_list()) {
            auto type = static_cast<llvm::Type *>(i->get_type()->accept(this));
            if (llvm::Type::TypeID::IntegerTyID != type->getTypeID() && llvm::Type::TypeID::DoubleTyID != type->getTypeID()) {
                error("record only support simple field type");
                return nullptr;
            }
            for (int j = 0; j < i->get_id_list()->get_id_list().size(); j++) {
                elem.push_back(type);
            }
        }
        return llvm::StructType::get(*TheContext, elem);
    }

    void *visit(FieldListAST *node) final { return nullptr; }

    void *visit(FieldAST *node) final { return nullptr; }

    void *visit(StatementAST *node) final { return nullptr; }

    void *visit(ProcedureStatementAST *node) final {
        if ("read" == node->get_pro_name() || "write" == node->get_pro_name() || "readln" == node->get_pro_name() || "writeln" == node->get_pro_name()) {
            auto io = new IOProcedureStatementAST(node->get_pro_name(), node->get_param_list());
            io->accept(this);
            return nullptr;
        }
        else {
            (new FunctionDesignatorAST(node->get_pro_name(), node->get_param_list()))->accept(this);
        }
        return nullptr;
    }

    void *visit(IOProcedureStatementAST *node) final {
        if ("write" == node->get_pro_name() || "writeln" == node->get_pro_name()) {
            if (nullptr == Printf) {
                PrintfTy = llvm::FunctionType::get(llvm::Type::getInt32Ty(*TheContext), {llvm::Type::getInt8PtrTy(*TheContext)}, true);
                Printf = llvm::Function::Create(PrintfTy, llvm::Function::ExternalLinkage, "printf", *TheModule);
            }
            std::vector<llvm::Value *> buffer;
            std::set<int> nospace;
            for (auto *i : node->get_param_list()->get_actual_param_list()) {
                if (ExpressionAST::Type::CONSTANT == i->get_expression()->type()) {
                    auto cons = static_cast<UnsignedConstantAST *>(i->get_expression())->get_value();
                    if (ConstantAST::Type::IDENTIFIER == cons->type()) {
                        auto symbol = SymbolStack->find(cons->value());
                        if (nullptr == symbol) {
                            error("identifier \"%s\" is undefined", cons->value().c_str());
                            return nullptr;
                        }
                        if (Symbol::Type::VARIABLE == symbol->type()) {
                            auto var = std::dynamic_pointer_cast<SymbolVariable>(symbol);
                            if (nullptr == var->getTypeSymbol()) {
                                ;
                            }
                            else if (Symbol::Type::ARRAY == var->getTypeSymbol()->type()) {
                                auto beg = std::dynamic_pointer_cast<SymbolArray>(var->getTypeSymbol())->getIndexBegin();
                                auto end = std::dynamic_pointer_cast<SymbolArray>(var->getTypeSymbol())->getIndexEnd();
                                for (int j = beg; j <= end; j++) {
                                    auto index = new IndexExpressionListAST();
                                    index->push_back(new IndexExpressionAST(new UnsignedConstantAST(new ConstantAST(
                                        ConstantAST::Type::INTEGER, std::to_string(j)))));
                                    auto ref = new IndexedVariableAST(cons->value(), index);
                                    auto val = Builder->CreateLoad(static_cast<llvm::Value *>(ref->accept(this)));
                                    if (val->getType()->isIntegerTy(8)) {
                                        nospace.insert(buffer.size());
                                    }
                                    buffer.push_back(val);
                                }
                                auto it = nospace.find(buffer.size() - 1);
                                if (it != nospace.end()) {
                                    nospace.erase(it);
                                }
                                continue;
                            }
                            else if (Symbol::Type::RECORD == var->getTypeSymbol()->type()) {
                                // auto rec = std::dynamic_pointer_cast<SymbolRecord>(symbol)->getRecord();
                                auto field = std::dynamic_pointer_cast<SymbolRecord>(var->getTypeSymbol())->getField();
                                for (auto &j : field) {
                                    auto ref = new FieldDesignatorAST(cons->value(), j);
                                    buffer.push_back(static_cast<llvm::Value *>(ref->accept(this)));
                                }
                                continue;
                            }
                        }
                    }
                }
                buffer.push_back(static_cast<llvm::Value *>(i->get_expression()->accept(this)));
            }

            for (auto it = buffer.begin(); it != buffer.end(); it++) {
                if ((*it)->getType()->isPointerTy()) {
                    if ((*it)->getType()->getPointerElementType()->isArrayTy()) {
                        continue;
                    }
                    *it = Builder->CreateLoad(*it);
                }
            }

            std::vector<llvm::Value *> args;
            std::string format;
            for (int i = 0; i < buffer.size(); i++) {
                if (buffer[i]->getType()->isIntegerTy(1)) {
                    format += "%d";
                    args.push_back(buffer[i]);
                }
                else if (buffer[i]->getType()->isIntegerTy(8)) {
                    format += "%c";
                    args.push_back(buffer[i]);
                }
                else if (buffer[i]->getType()->isIntegerTy(32)) {
                    format += "%d";
                    args.push_back(buffer[i]);
                }
                else if (buffer[i]->getType()->isDoubleTy()) {
                    format += "%f";
                    args.push_back(buffer[i]);
                }
                else if (buffer[i]->getType()->isPointerTy()) {
                    format += "%s";
                    args.push_back(buffer[i]);
                }
                if (nospace.find(i) == nospace.end()) {
                    format.push_back(' ');
                }
            }
            format += "\n";
            args.insert(args.begin(), Builder->CreateGlobalStringPtr(format));
            Builder->CreateCall(Printf, args);
        }

        else if ("read" == node->get_pro_name() || "readln" == node->get_pro_name()) {
            if (nullptr == Scanf) {
                ScanfTy = llvm::FunctionType::get(llvm::Type::getInt32Ty(*TheContext), {llvm::Type::getInt8PtrTy(*TheContext)}, true);
                Scanf = llvm::Function::Create(ScanfTy, llvm::Function::ExternalLinkage, "scanf", *TheModule);
            }
            std::vector<llvm::Value *> buffer;
            for (auto *i : node->get_param_list()->get_actual_param_list()) {
                buffer.push_back(static_cast<llvm::Value *>(i->get_expression()->accept(this)));
            }
            std::vector<llvm::Value *> args;
            std::string format;
            for (auto &i : buffer) {
                auto ptr = i;
                if (!ptr->getType()->isPointerTy()) {
                    error("not valid lvalue in read");
                    return nullptr;
                }
                if (ptr->getType()->getPointerElementType()->isIntegerTy(8)) {
                    format += "%c";
                    args.push_back(ptr);
                }
                else if (ptr->getType()->getPointerElementType()->isIntegerTy(32)) {
                    format += "%d";
                    args.push_back(ptr);
                }
                else if (ptr->getType()->getPointerElementType()->isDoubleTy()) {
                    format += "%lf";
                    args.push_back(ptr);
                }
                else {
                    error("not acceptable simple lvalue in read");
                    return nullptr;
                }
            }
            args.insert(args.begin(), Builder->CreateGlobalStringPtr(format));
            Builder->CreateCall(Scanf, args);
            // Builder->CreateCall(Scanf, Builder->CreateGlobalStringPtr("%*[^\n]"));
            // Builder->CreateCall(llvm::Function::Create(
            //     llvm::FunctionType::get(llvm::Type::getInt32Ty(*TheContext), false),
            //     llvm::Function::ExternalLinkage, "getchar", *TheModule));
        }

        return nullptr;
    }

    void *visit(ActualParameterListAST *node) final { return nullptr; }

    void *visit(ReadParameterListAST *node) final { return nullptr; }

    void *visit(WriteParameterList *node) final { return nullptr; }

    void *visit(ActualParameterAST *node) final {
        // Procedure and function call nodes should handle params themselves
        // This visit should not be called
        // return node->get_expression()->accept(this);
        return nullptr;
    }

    void *visit(StatementPartAST *node) final {
        return node->get_compound_statement()->accept(this);
    }

    void *visit(CompoundStatement *node) final {
        return node->get_statement_list()->accept(this);
    }

    void *visit(StatementSequenceAST *node) final {
        for (auto &i : node->get_statement_list()) {
            i->accept(this);
        }
        return nullptr;
    }

    void *visit(EmptyStatementAST *node) final { return nullptr; }

    void *visit(AssignmentStatementAST *node) final {
        auto lhs = static_cast<llvm::Value *>(node->get_lhs()->accept(this));
        auto rhs = static_cast<llvm::Value *>(node->get_rhs()->accept(this));
        if (!lhs->getType()->isPointerTy()) {
            error("assign left hand side is not valid lvalue");
            return nullptr;
        }
        if (rhs->getType()->isPointerTy()) {
            rhs = Builder->CreateLoad(rhs);
        }
        auto ltype = lhs->getType()->getPointerElementType();
        auto rtype = rhs->getType();
        if (ltype != rtype) {
            if (ltype->isDoubleTy() && rtype->isIntegerTy()) {
                rhs = Builder->CreateSIToFP(rhs, ltype);
            }
            else if (ltype->isIntegerTy() && rtype->isDoubleTy()) {
                rhs = Builder->CreateFPToSI(rhs, ltype);
                warning("assign real to integer");
            }
            else {
                error("assign incompatible type");
                return nullptr;
            }
        }
        Builder->CreateStore(rhs, lhs);
        return nullptr;
    }

    void *visit(IfStatementAST *node) final {
        llvm::Function *func = Builder->GetInsertBlock()->getParent();

        llvm::BasicBlock *thenBlock = llvm::BasicBlock::Create(*TheContext, "then", func);
        llvm::BasicBlock *elseBlock = llvm::BasicBlock::Create(*TheContext, "else", func);
        llvm::BasicBlock *contBlock = llvm::BasicBlock::Create(*TheContext, "cont", func); //条件块
        //条件的结果，1位整型
        llvm::Value *cmpValue = static_cast<llvm::Value *>(node->get_expression()->accept(this));
        if (nullptr == cmpValue) {
            error("Invalid condition in if statement");
            return nullptr;
        }
        if (cmpValue->getType()->isPointerTy()) {
            cmpValue = Builder->CreateLoad(cmpValue);
        }
        if (!cmpValue->getType()->isIntegerTy(1)) {
            error("Invalid condition in if statement");
            return nullptr;
        }

        Builder->CreateCondBr(cmpValue, thenBlock, elseBlock);

        Builder->SetInsertPoint(thenBlock);
        node->get_then_statement()->accept(this);
        Builder->CreateBr(contBlock);

        Builder->SetInsertPoint(elseBlock);

        if (nullptr != node->get_else_statement()) {
            node->get_else_statement()->accept(this);
        }

        // func->getBasicBlockList().push_back(contBlock);

        Builder->CreateBr(contBlock);
        Builder->SetInsertPoint(contBlock);

        return nullptr;
    }

    void *visit(CaseStatementAST *node) final {
        llvm::Value *vE = static_cast<llvm::Value *>(node->get_expression()->accept(this));
        llvm::Value *v = Builder->CreateLoad(vE);

        //支持的类型
        if (!v->getType()->isIntegerTy()) {
            error("Incompatible type in case statement");
            return nullptr;
        }
        
        llvm::Function *func = Builder->GetInsertBlock()->getParent();
        llvm::BasicBlock *cont = llvm::BasicBlock::Create(*TheContext, "cont");

        std::vector<CaseListElementAST *> branchList = node->get_case_body()->get_banch_list();
        //所有的case语句数，有多个值的打开成多条case
        int allCaseNum = 0;
        for (CaseListElementAST *branch : branchList) {
            allCaseNum += branch->get_const_list()->get_const_list().size();
        }

        auto *switchStatement = Builder->CreateSwitch(v, cont, allCaseNum);


        for (CaseListElementAST *branch : branchList) {
            std::vector<ConstantAST *> constList = branch->get_const_list()->get_const_list();
            //每个值产生一个case
            for (ConstantAST *constAst : constList) {
                //只支持int
                llvm::ConstantInt *constantValue = static_cast<llvm::ConstantInt *>(constAst->accept(this));

                //需不需要区分是定义在const部分的常量，还是字面常量

                llvm::BasicBlock *block = llvm::BasicBlock::Create(*TheContext, "case", func);
                Builder->SetInsertPoint(block);
                branch->get_statement()->accept(this);
                Builder->CreateBr(cont);
                switchStatement->addCase(constantValue, block);
            }
        }
        func->getBasicBlockList().push_back(cont);
        Builder->SetInsertPoint(cont);

        return nullptr;
    }

    void *visit(RepeatStatementAST *node) final {
        llvm::Function *func = Builder->GetInsertBlock()->getParent();

        llvm::BasicBlock *bodyBlock = llvm::BasicBlock::Create(*TheContext, "repeat", func);
        Builder->CreateBr(bodyBlock);
        Builder->SetInsertPoint(bodyBlock);

        node->get_statement_list()->accept(this);

        llvm::Value *cond = static_cast<llvm::Value *>(node->get_expression()->accept(this));

        if (cond == nullptr || !cond->getType()->isIntegerTy(1)) {
            error("Incompatible type in repeat statement");
            return nullptr;
        }

        llvm::BasicBlock *cont = llvm::BasicBlock::Create(*TheContext, "cont", func);
        Builder->CreateCondBr(cond, cont, bodyBlock);

        Builder->SetInsertPoint(cont);

        return nullptr;
    }

    void *visit(WhileStatementAST *node) final {
        llvm::Function *func = Builder->GetInsertBlock()->getParent();

        llvm::BasicBlock *whileBlock = llvm::BasicBlock::Create(*TheContext, "while", func);
        llvm::BasicBlock *loopBlock = llvm::BasicBlock::Create(*TheContext, "loop", func);
        llvm::BasicBlock *contBlock = llvm::BasicBlock::Create(*TheContext, "cont", func);

        Builder->CreateBr(whileBlock);
        Builder->SetInsertPoint(whileBlock);

        llvm::Value *cond = static_cast<llvm::Value *>(node->get_expression()->accept(this));
        if (cond == nullptr || !cond->getType()->isIntegerTy(1)) {
            error("Incompatible type in while statement");
            return nullptr;
        }

        Builder->CreateCondBr(cond, loopBlock, contBlock);

        Builder->SetInsertPoint(loopBlock);
        node->get_statement()->accept(this);

        Builder->CreateBr(whileBlock);

        // func->getBasicBlockList().push_back(contBlock);
        Builder->SetInsertPoint(contBlock);

        return nullptr;
    }

    void *visit(ForStatementAST *node) final {
        llvm::Function *func = Builder->GetInsertBlock()->getParent();

        llvm::BasicBlock *forBlock = llvm::BasicBlock::Create(*TheContext, "for", func);
        llvm::BasicBlock *loopBlock = llvm::BasicBlock::Create(*TheContext, "loop", func);
        llvm::BasicBlock *contBlock = llvm::BasicBlock::Create(*TheContext, "cont", func);

        llvm::Value *idValue = static_cast<llvm::Value *>(node->get_id()->accept(this));
        llvm::Value *initialValue = static_cast<llvm::Value *>(node->get_initial_value()->accept(this));
        if (initialValue->getType()->isPointerTy()) {
            initialValue = Builder->CreateLoad(initialValue);
        }
        llvm::Value *endCurVar = static_cast<llvm::Value *>(node->get_endvalue()->accept(this));
        if (endCurVar->getType()->isPointerTy()) {
            endCurVar = Builder->CreateLoad(endCurVar);
        }
        llvm::Value *consValue = llvm::ConstantInt::get(llvm::Type::getInt32Ty(*TheContext), 1);

        Builder->CreateStore(initialValue, idValue);
        Builder->CreateBr(forBlock);

        // for Basic Block
        Builder->SetInsertPoint(forBlock);
        switch (node->get_direction()) {
        case ForStatementAST::ForDirection::OP_TO: {
            llvm::Value *idCurVar = Builder->CreateLoad(idValue);
            llvm::Value *cmp = Builder->CreateICmpSLT(idCurVar, endCurVar);
            Builder->CreateCondBr(cmp, loopBlock, contBlock);
            break;
        }
        case ForStatementAST::ForDirection::OP_DOWNTO: {
            llvm::Value *idCurVar = Builder->CreateLoad(idValue);
            llvm::Value *cmp = Builder->CreateICmpSGT(idCurVar, endCurVar);
            Builder->CreateCondBr(cmp, loopBlock, contBlock);
            break;
        }
        default:
            break;
        }
        // loop Basic Block
        Builder->SetInsertPoint(loopBlock);
        node->get_statement()->accept(this);
        switch (node->get_direction()) {
        case ForStatementAST::ForDirection::OP_TO: {
            // i++
            llvm::Value *CurVar = Builder->CreateLoad(idValue);                    // Read id
            llvm::Value *NextVar = Builder->CreateAdd(CurVar, consValue, "op_to"); // id++
            Builder->CreateStore(NextVar, idValue);                                // Update id
            break;
        }
        case ForStatementAST::ForDirection::OP_DOWNTO: {
            // i--
            llvm::Value *CurVar = Builder->CreateLoad(idValue);                        // Read id
            llvm::Value *NextVar = Builder->CreateSub(CurVar, consValue, "op_downto"); // id--
            Builder->CreateStore(NextVar, idValue);                                    // Update id
            break;
        }
        default:
            break;
        }
        Builder->CreateBr(forBlock);
        // cont Basic Block
        Builder->SetInsertPoint(contBlock);

        return nullptr;
    }

    void *visit(CaseListElementListAST *node) final { return nullptr; }

    void *visit(CaseListElementAST *node) final { return nullptr; }

    void *visit(CaseConstantListAST *node) final { return nullptr; }

    void *visit(ExpressionAST *node) final { return nullptr; }

    void *visit(UnsignedConstantAST *node) final {
        return node->get_value()->accept(this);
    }

    void *visit(IdentifierAST *node) final {
        auto symbol = SymbolStack->find(node->get_name());
        if (nullptr == symbol) {
            error("identifier \"%s\" is undefined", node->get_name().c_str());
        }
        if (Symbol::Type::VARIABLE == symbol->type()) {
            return std::dynamic_pointer_cast<SymbolVariable>(symbol)->getValue();
        }
        else if (Symbol::Type::CONSTANT == symbol->type()) {
            return std::dynamic_pointer_cast<SymbolConstant>(symbol)->getValue();
        }
        else {
            error("identifier \"%s\" is not variable or constant", node->get_name().c_str());
            return nullptr;
        }
    }

    void *visit(BinaryAST *node) final {
        llvm::Value *lhs_value = nullptr;
        llvm::Value *rhs_value = nullptr;

        if (node->get_lhs() != nullptr) {
            lhs_value = static_cast<llvm::Value *>(node->get_lhs()->accept(this));
            if (lhs_value && lhs_value->getType()->isPointerTy()) {
                lhs_value = Builder->CreateLoad(lhs_value);
            }
        }
        if(node->get_rhs()!=nullptr){
            rhs_value = static_cast<llvm::Value *>(node->get_rhs()->accept(this));
            if (rhs_value && rhs_value->getType()->isPointerTy()) {
                rhs_value = Builder->CreateLoad(rhs_value);
            }
        }
        
        switch (node->get_op()) {
        case BinaryAST::OpType::OP_ADD: {
            if (lhs_value->getType()->isIntegerTy() && rhs_value->getType()->isIntegerTy()) {
                return Builder->CreateAdd(lhs_value, rhs_value, "addop");
            }
            else if (lhs_value->getType()->isIntegerTy() && !rhs_value->getType()->isIntegerTy()) {
                auto lhs = Builder->CreateSIToFP(lhs_value, rhs_value->getType());
                return Builder->CreateFAdd(lhs, rhs_value, "faddop");
            }
            else if (!lhs_value->getType()->isIntegerTy() && rhs_value->getType()->isIntegerTy()) {
                auto rhs = Builder->CreateSIToFP(rhs_value, lhs_value->getType());
                return Builder->CreateFAdd(lhs_value, rhs, "faddop");
            }
            else {
                return Builder->CreateFAdd(lhs_value, rhs_value, "faddop");
            }
            break;
        }
        case BinaryAST::OpType::OP_SUB: {
            if(lhs_value == nullptr){
                lhs_value = llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(*TheContext), 0);
            }
            if(rhs_value == nullptr){
                rhs_value = llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(*TheContext), 0);
            }
            if (lhs_value->getType()->isIntegerTy() && rhs_value->getType()->isIntegerTy()) {
                return Builder->CreateSub(lhs_value, rhs_value, "subop");
            }
            else if (lhs_value->getType()->isIntegerTy() && !rhs_value->getType()->isIntegerTy()) {
                auto lhs = Builder->CreateSIToFP(lhs_value, rhs_value->getType());
                return Builder->CreateFSub(lhs, rhs_value, "fsubop");
            }
            else if (!lhs_value->getType()->isIntegerTy() && rhs_value->getType()->isIntegerTy()) {
                auto rhs = Builder->CreateSIToFP(rhs_value, lhs_value->getType());
                return Builder->CreateFSub(lhs_value, rhs, "fsubop");
            }
            else {
                return Builder->CreateFSub(lhs_value, rhs_value, "fsubop");
            }
            break;
        }
        case BinaryAST::OpType::OP_MUL: {
            if (lhs_value->getType()->isIntegerTy() && rhs_value->getType()->isIntegerTy())
                return Builder->CreateMul(lhs_value, rhs_value, "mulop");
            else if (lhs_value->getType()->isIntegerTy() && !rhs_value->getType()->isIntegerTy()) {
                auto lhs = Builder->CreateSIToFP(lhs_value, rhs_value->getType());
                return Builder->CreateFMul(lhs, rhs_value, "fmulop");
            }
            else if (!lhs_value->getType()->isIntegerTy() && rhs_value->getType()->isIntegerTy()) {
                auto rhs = Builder->CreateSIToFP(rhs_value, lhs_value->getType());
                return Builder->CreateFMul(lhs_value, rhs, "fmulop");
            }
            else
                return Builder->CreateFMul(lhs_value, rhs_value, "fmulop");
            break;
        }
        case BinaryAST::OpType::OP_DIV: {
            if (lhs_value->getType()->isIntegerTy() && rhs_value->getType()->isIntegerTy())
                return Builder->CreateUDiv(lhs_value, rhs_value, "divop");
            else if (lhs_value->getType()->isIntegerTy() && !rhs_value->getType()->isIntegerTy()) {
                auto lhs = Builder->CreateSIToFP(lhs_value, rhs_value->getType());
                return Builder->CreateFDiv(lhs, rhs_value, "fdivop");
            }
            else if (!lhs_value->getType()->isIntegerTy() && rhs_value->getType()->isIntegerTy()) {
                auto rhs = Builder->CreateSIToFP(rhs_value, lhs_value->getType());
                return Builder->CreateFDiv(lhs_value, rhs, "fdivop");
            }
            else
                return Builder->CreateFDiv(lhs_value, rhs_value, "fdivop");
            break;
        }
        case BinaryAST::OpType::OP_MOD: {
            if (lhs_value->getType()->isIntegerTy() && rhs_value->getType()->isIntegerTy()) {
                return Builder->CreateURem(lhs_value, rhs_value, "modop");
            }
            else if (lhs_value->getType()->isIntegerTy() && !rhs_value->getType()->isIntegerTy()) {
                auto lhs = Builder->CreateSIToFP(lhs_value, rhs_value->getType());
                return Builder->CreateFRem(lhs, rhs_value, "fmodop");
            }
            else if (!lhs_value->getType()->isIntegerTy() && rhs_value->getType()->isIntegerTy()) {
                auto rhs = Builder->CreateSIToFP(rhs_value, lhs_value->getType());
                return Builder->CreateFRem(lhs_value, rhs, "fmodop");
            }
            else
                return Builder->CreateFRem(lhs_value, rhs_value, "fmodop");
            break;
        }
        case BinaryAST::OpType::OP_INC: {
            return nullptr;
        }
        case BinaryAST::OpType::OP_DEC: {
            return nullptr;
        }
        case BinaryAST::OpType::OP_EQ: {
            if (lhs_value->getType()->isIntegerTy() && rhs_value->getType()->isIntegerTy()) {
                return Builder->CreateICmpEQ(lhs_value, rhs_value, "eqop");
            }
            else if (lhs_value->getType()->isIntegerTy() && !rhs_value->getType()->isIntegerTy()) {
                auto lhs = Builder->CreateSIToFP(lhs_value, rhs_value->getType());
                return Builder->CreateFCmpUEQ(lhs, rhs_value, "feqop");
            }
            else if (!lhs_value->getType()->isIntegerTy() && rhs_value->getType()->isIntegerTy()) {
                auto rhs = Builder->CreateSIToFP(rhs_value, lhs_value->getType());
                return Builder->CreateFCmpUEQ(lhs_value, rhs, "feqop");
            }
            else {
                return Builder->CreateFCmpUEQ(lhs_value, rhs_value, "feqop");
            }
            break;
        }
        case BinaryAST::OpType::OP_NE: {
            if (lhs_value->getType()->isIntegerTy() && rhs_value->getType()->isIntegerTy()) {
                return Builder->CreateICmpNE(lhs_value, rhs_value, "neop");
            }
            else if (lhs_value->getType()->isIntegerTy() && !rhs_value->getType()->isIntegerTy()) {
                auto lhs = Builder->CreateSIToFP(lhs_value, rhs_value->getType());
                return Builder->CreateFCmpUNE(lhs, rhs_value, "fneop");
            }
            else if (!lhs_value->getType()->isIntegerTy() && rhs_value->getType()->isIntegerTy()) {
                auto rhs = Builder->CreateSIToFP(rhs_value, lhs_value->getType());
                return Builder->CreateFCmpUNE(lhs_value, rhs, "fneop");
            }
            else {
                return Builder->CreateFCmpUNE(lhs_value, rhs_value, "fneop");
            }
            break;
        }
        case BinaryAST::OpType::OP_LT: {
            if (lhs_value->getType()->isIntegerTy() && rhs_value->getType()->isIntegerTy()) {
                return Builder->CreateICmpULT(lhs_value, rhs_value, "ltop");
            }
            else if (lhs_value->getType()->isIntegerTy() && !rhs_value->getType()->isIntegerTy()) {
                auto lhs = Builder->CreateSIToFP(lhs_value, rhs_value->getType());
                return Builder->CreateFCmpULT(lhs, rhs_value, "fltop");
            }
            else if (!lhs_value->getType()->isIntegerTy() && rhs_value->getType()->isIntegerTy()) {
                auto rhs = Builder->CreateSIToFP(rhs_value, lhs_value->getType());
                return Builder->CreateFCmpULT(lhs_value, rhs, "fltop");
            }
            else {
                return Builder->CreateFCmpULT(lhs_value, rhs_value, "fltop");
            }
            break;
        }
        case BinaryAST::OpType::OP_LE: {
            if (lhs_value->getType()->isIntegerTy() && rhs_value->getType()->isIntegerTy()) {
                return Builder->CreateICmpULE(lhs_value, rhs_value, "leop");
            }
            else if (lhs_value->getType()->isIntegerTy() && !rhs_value->getType()->isIntegerTy()) {
                auto lhs = Builder->CreateSIToFP(lhs_value, rhs_value->getType());
                return Builder->CreateFCmpULE(lhs, rhs_value, "fleop");
            }
            else if (!lhs_value->getType()->isIntegerTy() && rhs_value->getType()->isIntegerTy()) {
                auto rhs = Builder->CreateSIToFP(rhs_value, lhs_value->getType());
                return Builder->CreateFCmpULE(lhs_value, rhs, "fleop");
            }
            else {
                return Builder->CreateFCmpULE(lhs_value, rhs_value, "fleop");
            }
            break;
        }
        case BinaryAST::OpType::OP_GT: {
            if (lhs_value->getType()->isIntegerTy() && rhs_value->getType()->isIntegerTy()) {
                return Builder->CreateICmpUGT(lhs_value, rhs_value, "gtop");
            }
            else if (lhs_value->getType()->isIntegerTy() && !rhs_value->getType()->isIntegerTy()) {
                auto lhs = Builder->CreateSIToFP(lhs_value, rhs_value->getType());
                return Builder->CreateFCmpUGT(lhs, rhs_value, "fgtop");
            }
            else if (!lhs_value->getType()->isIntegerTy() && rhs_value->getType()->isIntegerTy()) {
                auto rhs = Builder->CreateSIToFP(rhs_value, lhs_value->getType());
                return Builder->CreateFCmpUGT(lhs_value, rhs, "fgtop");
            }
            else {
                return Builder->CreateFCmpUGT(lhs_value, rhs_value, "fgtop");
            }
            break;
        }
        case BinaryAST::OpType::OP_GE: {
            if (lhs_value->getType()->isIntegerTy() && rhs_value->getType()->isIntegerTy()) {
                return Builder->CreateICmpUGE(lhs_value, rhs_value, "geop");
            }
            else if (lhs_value->getType()->isIntegerTy() && !rhs_value->getType()->isIntegerTy()) {
                auto lhs = Builder->CreateSIToFP(lhs_value, rhs_value->getType());
                return Builder->CreateFCmpUGE(lhs, rhs_value, "fgeop");
            }
            else if (!lhs_value->getType()->isIntegerTy() && rhs_value->getType()->isIntegerTy()) {
                auto rhs = Builder->CreateSIToFP(rhs_value, lhs_value->getType());
                return Builder->CreateFCmpUGE(lhs_value, rhs, "fgeop");
            }
            else {
                return Builder->CreateFCmpUGE(lhs_value, rhs_value, "fgeop");
            }
            break;
        }
        case BinaryAST::OpType::OP_AND: {
            return Builder->CreateAnd(lhs_value, rhs_value, "andop");
            break;
        }
        case BinaryAST::OpType::OP_OR: {
            return Builder->CreateOr(lhs_value, rhs_value, "orop");
            break;
        }
        case BinaryAST::OpType::OP_NOT: {
            if (rhs_value != nullptr) {
                return Builder->CreateNot(rhs_value, "notop");
                break;
            }
            else if(lhs_value != nullptr){
                return Builder->CreateNot(lhs_value,"notop");
                break;
            }
            else {
                error("invalid NOT");
                return nullptr;
                break;
            }
        }
        default: {
            error("Invalid binary operator");
            return nullptr;
            break;
        }
        }
    }

    void *visit(IndexedVariableAST *node) final {
        std::string array_name = node->get_array_name();
        llvm::Value *index = static_cast<llvm::Value *>(node->get_indices()->accept(this));

        std::shared_ptr<Symbol> symbol = SymbolStack->find(array_name);
        if (symbol == nullptr || symbol->type() != Symbol::Type::VARIABLE) {
            error("Cannot find this array!");
            return nullptr;
        }

        auto array_variable = std::dynamic_pointer_cast<SymbolVariable>(symbol);
        if (array_variable->getTypeSymbol()->type() != Symbol::Type::ARRAY) {
            error("Not an ARRAY type!");
            return nullptr;
        }

        llvm::Value *array = array_variable->getValue();
        auto array_symbol = std::dynamic_pointer_cast<SymbolArray>(array_variable->getTypeSymbol());
        int beg = array_symbol->getIndexBegin();
        int end = array_symbol->getIndexEnd();

        auto begin = llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(*TheContext), beg);
        auto left = Builder->CreateSub(index, begin);

        if (false) {
            // TBD out of the range
            error("The index is out of the range");
            return nullptr;
        }

        std::vector<llvm::Value *> indices;
        indices.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(*TheContext), 0));
        indices.push_back(left);
        return Builder->CreateGEP(array, indices);
    }

    void *visit(IndexExpressionListAST *node) final {
        std::vector<llvm::Value *> indicesValues;
        return node->get_indices()[0]->accept(this);
    }

    void *visit(IndexExpressionAST *node) final {
        llvm::Value *index = static_cast<llvm::Value *>(node->get_expression()->accept(this));
        if (index->getType()->isPointerTy()) {
            index = Builder->CreateLoad(index);
        }
        return index;
    }

    void *visit(FieldDesignatorAST *node) final {
        std::string name = node->get_record_name();
        std::string member = node->get_member();
        std::shared_ptr<Symbol> symbol = SymbolStack->find(name);

        if (symbol == nullptr || symbol->type() != Symbol::Type::VARIABLE) {
            error("Cannot find this RECORD!");
            return nullptr;
        }

        auto record_variable = std::dynamic_pointer_cast<SymbolVariable>(symbol);
        if (record_variable->getTypeSymbol()->type() != Symbol::Type::RECORD) {
            error("Not an RECORD type!");
            return nullptr;
        }

        auto record_symbol = std::dynamic_pointer_cast<SymbolRecord>(record_variable->getTypeSymbol());
        llvm::Value *record = record_variable->getValue();
        std::vector<std::string> field = record_symbol->getField();
        bool isMember = false;
        int index = -1;

        for (int i = 0; i < field.size(); i++) {
            if (field[i] == member) {
                isMember = true;
                index = i;
                break;
            }
        }
        if (isMember) {
            llvm::Value *const_index = llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(*TheContext), index);
            std::vector<llvm::Value *> indices;
            indices.push_back(llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(*TheContext), 0));
            indices.push_back(const_index);
            auto loaded_number = Builder->CreateGEP(record, indices);
            return loaded_number;
        }
        else {
            error("The member name in RECORD is ERROR!");
            return nullptr;
        }
    }

    void *visit(FunctionDesignatorAST *node) final {
        //实参
        std::vector<ActualParameterAST *> actualParamList = node->get_param_list()->get_actual_param_list();

        bool havaRgs = false; //是否有参数

        if (node->get_param_list() != nullptr) { //参数不为空
            havaRgs = true;
        }
        std::string funcName = node->get_func_name();
        log("Call %s\n", funcName.c_str());

        auto symbol = SymbolStack->find(funcName);
        if (nullptr == symbol) { //函数不存在
            error("Unkown function referenced[function %s not existed]", funcName.c_str());
            return nullptr;
        }

        llvm::Function *function;
        std::vector<bool> varpos;
        if (Symbol::Type::FUNCTION == symbol->type()) {
            function = std::dynamic_pointer_cast<SymbolFunction>(symbol)->getFunction();
            varpos = std::dynamic_pointer_cast<SymbolFunction>(symbol)->getVarPos();
        }
        else {
            error("identifier \"%s\" is not function", funcName.c_str());
            return nullptr;
        }

        if (function->arg_size() != actualParamList.size()) { //参数个数不对
            error("Incorrect arguments passed");
            return nullptr;
        }
        //处理实参
        std::vector<llvm::Value *> buffer; //用于调用的参数的缓存，下文进行类型判断
        for (ActualParameterAST *ap : actualParamList) {
            llvm::Value *v = static_cast<llvm::Value *>(ap->get_expression()->accept(this));
            if (nullptr == v) {
                error("param codegen result is nullptr");
                return nullptr;
            }
            buffer.push_back(v);
        }
        //检查参数的类型是否一致
        std::vector<llvm::Value *> params;
        int i = 0;
        for (llvm::Function::arg_iterator argIt = function->arg_begin(); argIt != function->arg_end(); argIt++, i++) {
            llvm::Type *argType = argIt->getType()->getPointerElementType();
            if ((buffer[i]->getType()->isPointerTy() && buffer[i]->getType()->getPointerElementType() != argType) || (!buffer[i]->getType()->isPointerTy() && buffer[i]->getType() != argType)) {
                error("params type not match");
                return nullptr;
            }
            if (false == varpos[i]) {
                llvm::Value *val;
                if (buffer[i]->getType()->isPointerTy()) {
                    val = Builder->CreateLoad(buffer[i]);
                }
                else {
                    val = buffer[i];
                }
                llvm::AllocaInst *temp = Builder->CreateAlloca(
                    val->getType(), nullptr, "__tmp" + std::to_string(TempParamCnt));
                Builder->CreateStore(val, temp);
                params.push_back(temp);
                TempParamCnt++;
            }
            else {
                if (!buffer[i]->getType()->isPointerTy()) {
                    error("cannot pass const as var");
                    return nullptr;
                }
                params.push_back(buffer[i]);
            }
        }

        //是否需要检查返回值类型
        return Builder->CreateCall(function, params);
    }
};

#endif
